﻿using System;
//using System.Drawing;
using System.Collections.Generic;
using System.Linq;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Media;

using Styx;
using Styx.Common;
using Styx.Common.Helpers;
using Styx.CommonBot;

using Styx.Helpers;


using Styx.WoWInternals;
using Styx.WoWInternals.DBC;
using Styx.WoWInternals.WoWObjects;

using Styx.CommonBot.Coroutines;
using Styx.CommonBot.Routines;
using Styx.CommonBot.POI;

using Styx.TreeSharp;
using Action = Styx.TreeSharp.Action;

using CommonBehaviors.Actions;





namespace KittyDru
{
    internal class Unit
    {
        private static LocalPlayer Me { get { return Styx.StyxWoW.Me; } }
        private static WoWUnit MyTarget
        {
            get
            {
                if (Me.GotTarget) return Me.CurrentTarget;
                return null;
            }
        }

        public static bool InLineOfSpellSight(WoWUnit unit, int timeOut = 1000)
        {
            if (unit != null && unit.InLineOfSpellSight)
            {
                return true;
            }

            return false;
        }

        public static float MeleeDistance(WoWUnit unit, WoWUnit atTarget = null)
        {
            // abort if mob null
            if (unit == null)
                return 0;

            // when called as SomeUnit.SpellDistance()
            // .. convert to SomeUnit.SpellDistance(Me)
            if (atTarget == null)
                atTarget = StyxWoW.Me;

            // when called as SomeUnit.SpellDistance(Me) then
            // .. convert to Me.SpellDistance(SomeUnit)
            if (atTarget.IsMe)
            {
                atTarget = unit;
                unit = StyxWoW.Me;
            }

            // pvp, then keep it close
            if (atTarget.IsPlayer && unit.IsPlayer)
                return 3.5f;

            return Math.Max(5f, atTarget.CombatReach + 1.3333334f + unit.CombatReach);
        }

        public static IEnumerable<WoWUnit> UnfriendlyUnits(int maxSpellDist)
        {
            Type typeWoWUnit = typeof(WoWUnit);
            Type typeWoWPlayer = typeof(WoWPlayer);
            List<WoWUnit> list = new List<WoWUnit>();
            List<WoWObject> objectList = ObjectManager.ObjectList;
            for (int i = 0; i < objectList.Count; i++)
            {
                Type type = objectList[i].GetType();
                if (type == typeWoWUnit || type == typeWoWPlayer)
                {
                    WoWUnit t = objectList[i] as WoWUnit;
                    if (t.IsUnit && t.SpellDistance() < maxSpellDist && t.IsValid && t.IsAlive && ValidUnit(t))
                    {
                      //  Utilities.log("Distance to {1} - {0}", t.SpellDistance(), t.SafeName);
                        list.Add(t);
                    }
                }
            }
            return list;
        }

        private static Color invalidColor = Colors.LightCoral;

        private const int BannerOfTheAlliance = 61573;
        private const int BannerOfTheHorde = 61574;

        public static bool IsTrainingDummy(WoWUnit unit)
        {
            // return Lists.BossList.TrainingDummies.Contains(unit.Entry);
            int bannerId = StyxWoW.Me.IsHorde ? BannerOfTheAlliance : BannerOfTheHorde;
            return unit != null && unit.Level > 1
                && ((unit.CurrentHealth == 1 && unit.MaxHealth < unit.Level) || unit.HasAura(bannerId));
        }


        public static bool ValidUnit(WoWUnit p, bool showReason = false)
        {
            if (p == null || !p.IsValid)
                return false;

            // Ignore shit we can't select
            if (!p.CanSelect)
            {
                if (showReason) Utilities.log(invalidColor, "invalid attack unit {0} cannot be Selected", p.SafeName);
                return false;
            }

            // Ignore shit we can't attack
            if (!p.Attackable)
            {
                if (showReason) Utilities.log(invalidColor, "invalid attack unit {0} cannot be Attacked", p.SafeName);
                return false;
            }

            // Duh
            if (p.IsDead)
            {
                if (showReason) Utilities.log(invalidColor, "invalid attack unit {0} is already Dead", p.SafeName);
                return false;
            }

            // check for enemy players here as friendly only seems to work on npc's
            if (p.IsPlayer)
            {
                WoWPlayer pp = p.ToPlayer();
                if (pp.IsHorde == StyxWoW.Me.IsHorde)
                {
                    if (showReason)
                        Utilities.log(invalidColor, "invalid attack player {0} not enemy", p.SafeName);
                    return false;
                }

                if (pp.Guid == StyxWoW.Me.CurrentTargetGuid && !Me.CurrentTarget.Attackable)
                {
                    if (showReason)
                        Utilities.log(invalidColor, "invalid attack player {0} cannot be Attacked currently", p.SafeName);
                    return false;
                }

                return true;
            }

            // Ignore friendlies!
            if (p.IsFriendly)
            {
                if (showReason) Utilities.log(invalidColor, "invalid attack unit {0} is Friendly", p.SafeName);
                return false;
            }

            // Dummies/bosses are valid by default. Period.
            if (IsTrainingDummy(p) || p.IsBoss)
                return true;

            // If it is a pet/minion/totem, lets find the root of ownership chain
            WoWPlayer pOwner = GetPlayerParent(p);

            // ignore if owner is player, alive, and not blacklisted then ignore (since killing owner kills it)
            // .. following .IsMe check to prevent treating quest mob summoned by us that we need to kill as invalid 
            if (pOwner != null && pOwner.IsAlive && !pOwner.IsMe)
            {
                if (!ValidUnit(pOwner))
                {
                    if (showReason)
                        Utilities.log(invalidColor, "invalid attack unit {0} not an attackable Player as Parent", p.SafeName);
                    return false;
                }
                if (!Blacklist.Contains(pOwner, BlacklistFlags.Combat))
                {
                    if (showReason)
                        Utilities.log(invalidColor, "valid attack unit {0} has an attackable Player as Parent", p.SafeName);
                    return false;
                }
                if (!StyxWoW.Me.IsPvPFlagged)
                {
                    if (showReason)
                        Utilities.log(invalidColor, "valid attackable player {0} but I am not PvP Flagged", p.SafeName);
                    return false;
                }
            }

            // And ignore non-combat pets
            if (p.IsNonCombatPet)
            {
                if (showReason) Utilities.log(invalidColor, "{0} is a Noncombat Pet", p.SafeName);
                return false;
            }

            // And ignore critters (except for those ferocious ones or if set as BotPoi)
            if (IsIgnorableCritter(p))
            {
                if (showReason) Utilities.log(invalidColor, "{0} is a Critter", p.SafeName);
                return false;
            }

            /*
                        if (p.CreatedByUnitGuid != 0 || p.SummonedByUnitGuid != 0)
                            return false;
            */
            return true;
        }

        public static bool IsIgnorableCritter(WoWUnit u)
        {
            if (!u.IsCritter)
                return false;

            // good enemy if BotPoi
            if (Styx.CommonBot.POI.BotPoi.Current.Guid == u.Guid && Styx.CommonBot.POI.BotPoi.Current.Type == Styx.CommonBot.POI.PoiType.Kill)
                return false;

            // good enemy if Targeting
            if (Targeting.Instance.TargetList.Contains(u))
                return false;

            // good enemy if Threat towards us
            if (u.ThreatInfo.ThreatValue != 0 && u.IsTargetingMyRaidMember)
                return false;

            // Nah, just a harmless critter
            return true;
        }


        public static WoWPlayer GetPlayerParent(WoWUnit unit)
        {
            // If it is a pet/minion/totem, lets find the root of ownership chain
            WoWUnit pOwner = unit;
            while (true)
            {
                if (pOwner.OwnedByUnit != null)
                    pOwner = pOwner.OwnedByRoot;
                else if (pOwner.CreatedByUnit != null)
                    pOwner = pOwner.CreatedByUnit;
                else if (pOwner.SummonedByUnit != null)
                    pOwner = pOwner.SummonedByUnit;
                else
                    break;
            }

            if (unit != pOwner && pOwner.IsPlayer)
                return pOwner as WoWPlayer;

            return null;
        }


    }
}
